package Main;

import StegoGUI.StegoFileSelection;
import java.io.*;
import java.net.URL;
import java.util.ArrayList;
import stego.Drivers;
import stego.StegoCreator.StegoEmbedder;
import stego.StegoCreator.StegoExtractor;
import stego.StegoReComposer.StegoReComposer_Caller;

public class Main
{

    public static final String strLoadGUI_1 = "Load GUI:  <null> ";
    public static final String strLoadGUI_2 = "Load GUI:  -g";
    public static final String strLoadEmbed = "Embed:\t   -e <source path> <carrier path> <4 char Batch ID> <DIR save path>";
    public static final String strLoadEmbed_Special = "Embed:\t   -eS <source> <carrier> <Batch ID> <Frag#> <#Frags Tot> <DIR save path" +
">"
;
    public static final String strExtract_1 = "Extract:   -x <carrier path> <extracted message save DIRECTORY path>";
    public static final String strReCompose = "ReCompose: -r <DIRECTORY path to carrier files>";
    public static boolean mode_CLI = false;
    public static boolean canLoad_GUI = false;
    public static boolean canLoad_EMBEDDER = false;
    public static boolean canLoad_EXTRACTOR = false;
    public static boolean canLoad_RECOMPOSER = false;
    public static String param_GUI = "-g";
    public static String param_USAGE = "-u";
    public static String param_HELP = "-h";
    public static String param_EMBED = "-e";
    public static String param_EMBED_SPECIAL = "-eS";
    public static String param_EXTRACT = "-x";
    public static String param_RECOMPOSE = "-r";
    public static String extractedMessage = "";

    public Main()
    {
    }

    public static void main(String args[])
    {
        try
        {
            initializePackagedClasses();
            if(canLoad_GUI && args == null || args.length < 1 || args[0] != null && args[0].trim().equalsIgnoreCase(param_GUI))
            {
                mode_CLI = false;
                call_GUI();
            } else
            if(canLoad_EMBEDDER && args[0] != null && args[0].trim().equalsIgnoreCase(param_EMBED))
            {
                mode_CLI = true;
                call_EMBEDDER(args);
            } else
            if(canLoad_EMBEDDER && args[0] != null && args[0].trim().equalsIgnoreCase(param_EMBED_SPECIAL))
            {
                mode_CLI = true;
                call_EMBEDDER_SPECIAL(args);
            } else
            if(canLoad_EXTRACTOR && args[0] != null && args[0].trim().equalsIgnoreCase(param_EXTRACT))
            {
                mode_CLI = true;
                call_EXTRACTOR(args);
            } else
            if(canLoad_RECOMPOSER && args[0] != null && args[0].trim().equalsIgnoreCase(param_RECOMPOSE))
            {
                mode_CLI = true;
                call_RECOMPOSER(args);
            } else
            if(args[0] != null && args[0].trim().equalsIgnoreCase(param_USAGE) || args[0].trim().equalsIgnoreCase(param_HELP))
            {
                mode_CLI = true;
                display_USAGE();
            } else
            {
                sop("Unknown load command specified.  Terminating program.");
                System.exit(0);
            }
        }
        catch(Exception e)
        {
            sop("Unable to load specified package.  Terminating program");
            System.exit(0);
        }
    }

    public static void initializePackagedClasses_GUI()
    {
        try
        {
            URL url_GUI = StegoGUI/StegoFileSelection.getResource("/StegoGUI/StegoFileSelection.class");
            if(url_GUI != null)
            {
                canLoad_GUI = true;
            }
        }
        catch(NoClassDefFoundError noclassdeffounderror) { }
        catch(Exception e)
        {
            sop("Exception caught in initializePackagedClasses_GUI mtd");
        }
    }

    public static void initializePackagedClasses_EMBEDDER()
    {
        try
        {
            URL url_EMBEDDER = Main/Main.getResource("/stego/StegoCreator/StegoEmbedder.class");
            if(url_EMBEDDER != null)
            {
                canLoad_EMBEDDER = true;
            }
        }
        catch(NoClassDefFoundError noclassdeffounderror) { }
        catch(Exception e)
        {
            sop("Exception caught in initializePackagedClasses_EMBEDDER mtd");
        }
    }

    public static void initializePackagedClasses_EXTRACTOR()
    {
        try
        {
            URL url_EXTRACTOR = Main/Main.getResource("/stego/StegoCreator/StegoExtractor.class");
            if(url_EXTRACTOR != null)
            {
                canLoad_EXTRACTOR = true;
            }
        }
        catch(NoClassDefFoundError noclassdeffounderror) { }
        catch(Exception e)
        {
            sop("Exception caught in initializePackagedClasses_EXTRACTOR mtd");
        }
    }

    public static void initializePackagedClasses_RECOMPOSER()
    {
        try
        {
            URL url_ReComposer_BatchAnalyzer = Main/Main.getResource("/stego/StegoReComposer/StegoReComposer_BatchAnalyzer.class");
            URL url_ReComposer_BatchCreator = Main/Main.getResource("/stego/StegoReComposer/StegoReComposer_BatchCreator.class");
            URL url_ReComposer_Caller = Main/Main.getResource("/stego/StegoReComposer/StegoReComposer_Caller.class");
            if(url_ReComposer_BatchAnalyzer != null && url_ReComposer_BatchCreator != null && url_ReComposer_Caller != null)
            {
                canLoad_RECOMPOSER = true;
            }
        }
        catch(NoClassDefFoundError noclassdeffounderror) { }
        catch(Exception e)
        {
            sop("Exception caught in initializePackagedClasses_RCOMPOSER mtd");
        }
    }

    public static void initializePackagedClasses()
    {
        initializePackagedClasses_GUI();
        initializePackagedClasses_EMBEDDER();
        initializePackagedClasses_EXTRACTOR();
        initializePackagedClasses_RECOMPOSER();
    }

    public static void initializePackagedClasses_OLD()
    {
        try
        {
            URL url_GUI = StegoGUI/StegoFileSelection.getResource("/StegoGUI/StegoFileSelection.class");
            if(url_GUI != null)
            {
                canLoad_GUI = true;
            }
            URL url_EMBEDDER = StegoGUI/StegoFileSelection.getResource("/stego/StegoCreator/StegoEmbedder.class");
            if(url_EMBEDDER != null)
            {
                canLoad_EMBEDDER = true;
            }
            URL url_EXTRACTOR = StegoGUI/StegoFileSelection.getResource("/stego/StegoCreator/StegoExtractor.class");
            if(url_EXTRACTOR != null)
            {
                canLoad_EXTRACTOR = true;
            }
            URL url_ReComposer_BatchAnalyzer = StegoGUI/StegoFileSelection.getResource("/stego/StegoReComposer/StegoReComposer_BatchAnalyzer.class");
            URL url_ReComposer_BatchCreator = StegoGUI/StegoFileSelection.getResource("/stego/StegoReComposer/StegoReComposer_BatchCreator.class");
            URL url_ReComposer_Caller = StegoGUI/StegoFileSelection.getResource("/stego/StegoReComposer/StegoReComposer_Caller.class");
            if(url_ReComposer_BatchAnalyzer != null && url_ReComposer_BatchCreator != null && url_ReComposer_Caller != null)
            {
                canLoad_RECOMPOSER = true;
            }
        }
        catch(NoClassDefFoundError noclassdeffounderror) { }
        catch(Exception e)
        {
            sop("Exception caught in initializePackagedClasses mtd");
        }
    }

    public static void call_GUI()
    {
        try
        {
            if(canLoad_GUI)
            {
                sop("Launching GUI.");
                StegoFileSelection frame = new StegoFileSelection();
                frame.setVisible(true);
            } else
            {
                throw new Exception("Expected Class Not Found");
            }
        }
        catch(Exception e)
        {
            sop((new StringBuilder("Invalid input received to call GUI. ")).append(e.getLocalizedMessage()).append(". Terminating Program.").toString());
            System.exit(0);
        }
    }

    public static void call_EMBEDDER(String params[])
    {
        try
        {
            if(params.length != 5)
            {
                throw new Exception("Insufficient parameters specified.");
            }
            File fleSource = new File(params[1]);
            File fleCarrier = new File(params[2]);
            String strBatchID = params[3];
            File fleSaveDir = new File(params[4]);
            if(fleSource == null || !fleSource.exists() || !fleSource.isFile())
            {
                throw new Exception("Source File Does not Exist.");
            }
            if(fleCarrier == null || !fleCarrier.exists() || !fleCarrier.isFile())
            {
                throw new Exception("Carrier File Does not Exist.");
            }
            if(fleSaveDir == null || !fleSaveDir.exists() || !fleSaveDir.isDirectory())
            {
                throw new Exception("Output Save Directory Does not Exist or is not a Directory.");
            }
            if(strBatchID == null || strBatchID.trim().length() != 4)
            {
                throw new Exception("Batch Identifier can only be 4 characters long.");
            }
            if(fleCarrier.length() < fleSource.length())
            {
                throw new Exception("Carrier File must be larger than source file to embed.");
            }
            byte arrCompleteSourceMsgToEmbed[] = Drivers.readImage_Fully(fleSource);
            byte arrSourceDateFileExtension[] = Drivers.getFileExtension_ByteArray(fleSource, true);
            int messageFileExtensionType = Drivers.getFileExtensionType(fleSource);
            String strMessageFileExtensionIndexType = Drivers.formatStringWithLeadingZeros((new StringBuilder()).append(messageFileExtensionType).toString(), 2);
            String strEmbedSize = (new StringBuilder()).append((int)fleSource.length()).toString();
            String maxEmbedSize = "6000";
            int leadingZerosNeededToFormatSize = maxEmbedSize.length() - strEmbedSize.length();
            for(int i = 0; i < leadingZerosNeededToFormatSize; i++)
            {
                strEmbedSize = (new StringBuilder("0")).append(strEmbedSize).toString();
                if(strEmbedSize.length() == maxEmbedSize.length())
                {
                    break;
                }
            }

            byte embedContentSize[] = strEmbedSize.getBytes();
            String currFragment = "00";
            String maxFragments = "01";
            sop("Launching Embedder");
            StegoEmbedder stegowriter = new StegoEmbedder(new File("./"), false, 0, new File("./"), arrCompleteSourceMsgToEmbed, embedContentSize, strBatchID.getBytes(), currFragment.getBytes(), maxFragments.getBytes(), strMessageFileExtensionIndexType.getBytes(), arrSourceDateFileExtension, fleCarrier, fleSaveDir);
        }
        catch(Exception e)
        {
            sop((new StringBuilder("Invalid input received to call EMBEDDER. ")).append(e.getLocalizedMessage()).append("\nTerminating Program.").toString());
            System.exit(0);
        }
    }

    public static void call_EMBEDDER_SPECIAL(String params[])
    {
        try
        {
            if(params.length != 7)
            {
                throw new Exception("Insufficient parameters specified.");
            }
            File fleSource = new File(params[1]);
            File fleCarrier = new File(params[2]);
            String strBatchID = params[3];
            String currFragment = params[4];
            String maxFragments = params[5];
            File fleSaveDir = new File(params[6]);
            if(fleSource == null || !fleSource.exists() || !fleSource.isFile())
            {
                throw new Exception("Source File Does not Exist.");
            }
            if(fleCarrier == null || !fleCarrier.exists() || !fleCarrier.isFile())
            {
                throw new Exception("Carrier File Does not Exist.");
            }
            if(fleSaveDir == null || !fleSaveDir.exists() || !fleSaveDir.isDirectory())
            {
                throw new Exception("Output Save Directory Does not Exist or is not a Directory.");
            }
            if(strBatchID == null || strBatchID.trim().length() != 4)
            {
                throw new Exception("Batch Identifier can only be 4 characters long.");
            }
            if(fleCarrier.length() < fleSource.length())
            {
                throw new Exception("Carrier File must be larger than source file to embed.");
            }
            byte arrCompleteSourceMsgToEmbed[] = Drivers.readImage_Fully(fleSource);
            byte arrSourceDateFileExtension[] = Drivers.getFileExtension_ByteArray(fleSource, true);
            int messageFileExtensionType = Drivers.getFileExtensionType(fleSource);
            String strMessageFileExtensionIndexType = Drivers.formatStringWithLeadingZeros((new StringBuilder()).append(messageFileExtensionType).toString(), 2);
            String strEmbedSize = (new StringBuilder()).append((int)fleSource.length()).toString();
            String maxEmbedSize = "6000";
            int leadingZerosNeededToFormatSize = maxEmbedSize.length() - strEmbedSize.length();
            for(int i = 0; i < leadingZerosNeededToFormatSize; i++)
            {
                strEmbedSize = (new StringBuilder("0")).append(strEmbedSize).toString();
                if(strEmbedSize.length() == maxEmbedSize.length())
                {
                    break;
                }
            }

            byte embedContentSize[] = strEmbedSize.getBytes();
            sop("Launching Embedder");
            StegoEmbedder stegowriter = new StegoEmbedder(new File("./"), false, 0, new File("./"), arrCompleteSourceMsgToEmbed, embedContentSize, strBatchID.getBytes(), currFragment.getBytes(), maxFragments.getBytes(), strMessageFileExtensionIndexType.getBytes(), arrSourceDateFileExtension, fleCarrier, fleSaveDir);
        }
        catch(Exception e)
        {
            sop((new StringBuilder("Invalid input received to call EMBEDDER_SPECIAL. ")).append(e.getLocalizedMessage()).append("\nTerminating Program.").toString());
            System.exit(0);
        }
    }

    public static void call_EXTRACTOR(String params[])
    {
        try
        {
            if(params.length != 3)
            {
                throw new Exception("Insufficient parameters specified.");
            }
            File fleCarrier = new File(params[1]);
            File fleSaveDir = new File(params[2]);
            if(fleCarrier == null || !fleCarrier.exists() || !fleCarrier.isFile())
            {
                throw new Exception("Carrier File Does not Exist.");
            }
            if(fleSaveDir == null || !fleSaveDir.exists() || !fleSaveDir.isDirectory())
            {
                throw new Exception("Output Save Directory Does not Exist or is not a Directory.");
            }
            StegoExtractor extractor = new StegoExtractor(false, fleCarrier, new File("./"), new File("./"));
            File fleExtractedMessage = null;
            String strTopFolderPath = fleSaveDir.getCanonicalPath();
            if(!strTopFolderPath.endsWith(System.getProperty("file.separator")))
            {
                fleExtractedMessage = new File((new StringBuilder(String.valueOf(strTopFolderPath))).append(System.getProperty("file.separator")).append(extractor.getBatchIdentifier()).append("_").append(extractor.getFragmentNumber()).append("_").append(extractor.getTotalNumberOfFragments()).append("_").append(".").append(extractor.getFileExtension_WithoutSpaceFiller()).toString());
            } else
            {
                fleExtractedMessage = new File((new StringBuilder(String.valueOf(strTopFolderPath))).append(extractor.getBatchIdentifier()).append("_").append(extractor.getFragmentNumber()).append("_").append(extractor.getTotalNumberOfFragments()).append("_").append(".").append(extractor.getFileExtension_WithoutSpaceFiller()).toString());
            }
            FileOutputStream fos = new FileOutputStream(fleExtractedMessage);
            fos.write(extractor.getExtractedMessage().getBytes());
            fos.flush();
            fos.close();
            Drivers.sop((new StringBuilder("\n# # # Extracted Message Successfully written at: ")).append(fleExtractedMessage.getCanonicalPath()).toString());
        }
        catch(Exception e)
        {
            sop((new StringBuilder("Invalid input received to call EXTRACTOR. ")).append(e.getLocalizedMessage()).append("\nTerminating Program.").toString());
            System.exit(0);
        }
    }

    public static void call_RECOMPOSER(String params[])
    {
        try
        {
            if(params.length != 2)
            {
                throw new Exception("Insufficient parameters specified.");
            }
            File fleSaveDir = new File(params[1]);
            if(fleSaveDir == null || !fleSaveDir.exists() || !fleSaveDir.isDirectory())
            {
                throw new Exception("Directory to analyze does not exist or is not a Directory.");
            }
            ArrayList selectedFiles = Drivers.getFilesUnderSelectedDirectory(fleSaveDir, null);
            StegoReComposer_Caller reComposer = null;
            if(selectedFiles != null && selectedFiles.size() > 0)
            {
                reComposer = new StegoReComposer_Caller(fleSaveDir, selectedFiles, false, new File("./"), new File("./"));
            } else
            if(selectedFiles == null || selectedFiles.size() < 1)
            {
                sop((new StringBuilder("No files were found under specified location:\n")).append(fleSaveDir.getCanonicalPath()).append("\nHowever, I will attempt to analyze already created Batch Directories under giv" +
"en folder path"
).toString());
                StegoReComposer_Caller.analyzeBatchDirectories(fleSaveDir);
            }
            sop("\n\nProcess complete.  Terminating program");
        }
        catch(Exception e)
        {
            sop("Invalid input received to call RECOMPOSER.  Terminating Program.");
            System.exit(0);
        }
    }

    public static void display_USAGE()
    {
        try
        {
            sop("\n* * * * USAGE INFORMATION * * * *");
            if(canLoad_GUI)
            {
                sop("Load GUI:  <null> ");
                sop("Load GUI:  -g");
            }
            if(canLoad_EMBEDDER)
            {
                sop("Embed:\t   -e <source path> <carrier path> <4 char Batch ID> <DIR save path>");
                sop("Embed:\t   -eS <source> <carrier> <Batch ID> <Frag#> <#Frags Tot> <DIR save path" +
">"
);
            }
            if(canLoad_EXTRACTOR)
            {
                sop("Extract:   -x <carrier path> <extracted message save DIRECTORY path>");
            }
            if(canLoad_RECOMPOSER)
            {
                sop("ReCompose: -r <DIRECTORY path to carrier files>");
            }
        }
        catch(Exception e)
        {
            sop("Invalid input received to display usage information.  Terminating Program.");
            System.exit(0);
        }
    }

    public static void sop(String strOut)
    {
        System.out.println(strOut);
    }

}
